set prefix=(memdisk)/boot/grub

insmod at_keyboard
insmod usb_keyboard
insmod nativedisk
insmod ehci
insmod ohci
insmod uhci
insmod usb
insmod usbms
insmod regexp

terminal_input --append at_keyboard
terminal_input --append usb_keyboard
terminal_output --append cbmemc

gfxpayload=keep
terminal_output --append gfxterm

if [ -f (cbfsdisk)/background.png ]; then
	insmod png
	background_image (cbfsdisk)/background.png
elif [ -f (cbfsdisk)/background.jpg ]; then
	insmod jpeg
	background_image (cbfsdisk)/background.jpg
fi

set default="0"
if [ -f (cbfsdisk)/timeout.cfg ]; then
	source (cbfsdisk)/timeout.cfg
else	
	set timeout=5
fi
set grub_scan_disk="both"
if [ -f (cbfsdisk)/scan.cfg ]; then
	source (cbfsdisk)/scan.cfg
fi

if [ -f (cbfsdisk)/keymap.gkb ]; then
	keymap (cbfsdisk)/keymap.gkb
elif [ -f (cbfsdisk)/keymap.cfg ]; then
	source (cbfsdisk)/keymap.cfg
else
	keymap usqwerty
fi

function try_user_config {
	set root="${1}"

	# The @/... entries are for cases where the BTRFS filesystem is being used
	for dir in boot grub grub2 boot/grub boot/grub2 @/boot @/grub @/grub2 @/boot/grub @/boot/grub2; do
		for name in '' osboot_ autoboot_ libreboot_ coreboot_; do
			if [ -f /"${dir}"/"${name}"grub.cfg ]; then
				unset superusers
				configfile /"${dir}"/"${name}"grub.cfg
			fi
		done
	done
}
function search_grub {
	echo -n "Attempting to load grub.cfg from '${1}' devices"
	for i in 0 1 2 3 4 5 6 7 8 9 10 11; do
		for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
			try_user_config "(${1}${i},${part})"
		done
		# raw devices e.g. (ahci0) instead of (ahci0,1)
		try_user_config "(${1}${i})"
	done
	echo # Insert newline
}

function try_isolinux_config {
	set root="${1}"
	for dir in '' /boot; do
		if [ -f "${dir}"/isolinux/isolinux.cfg ]; then
			syslinux_configfile -i "${dir}"/isolinux/isolinux.cfg
		elif [ -f "${dir}"/syslinux/syslinux.cfg ]; then
			syslinux_configfile -s "${dir}"/syslinux/syslinux.cfg
		fi
	done
}
function search_isolinux {
	echo "\nAttempting to parse isolinux/syslinux config from '${1}' devices"
	for i in 0 1 2 3 4 5 6 7 8 9 10 11; do
		for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
			try_isolinux_config "(${1}${i},${part})"
		done
		# raw devices e.g. (usb0) instead of (usb0,1)
		try_isolinux_config "(${1}${i})"
	done
	echo # Insert newline
}

function try_without_config {

}

menuentry 'Load Operating System (incl. fully encrypted disks)  [o]' --hotkey='o' {

	if [ "${grub_scan_disk}" != "ata" ]; then
		search_grub ahci
	fi
	if [ "${grub_scan_disk}" != "ahci" ]; then
		search_grub ata
	fi

	# grub device enumeration is very slow, so checks are hardcoded

	# TODO: add more strings, based on what distros set up when
	# the user select auto-partitioning on those installers
	lvmvol="lvm/grubcrypt-bootvol lvm/grubcrypt-rootvol"

	raidvol="md/0 md/1 md/2 md/3 md/4 md/5 md/6 md/7 md/8 md/9"

	# in practise, doing multiple redundant checks is perfectly fast and
	# TODO: optimize grub itself, and use */? here for everything

	for vol in ${lvmvol} ${raidvol} ; do
		try_user_config "${vol}"
	done

	unset ahcidev
	unset atadev
	for i in 11 10 9 8 7 6 5 4 3 2 1 0; do
		for part in 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1; do
			if [ "${grub_scan_disk}" != "ata" ]; then
				ahcidev="(ahci${i},${part}) ${ahcidev}"
			fi
			if [ "${grub_scan_disk}" != "ahci" ]; then
				atadev="(ata${i},${part}) ${atadev}"
			fi
		done
	done

	set pager=0
	echo -n "Attempting to unlock encrypted volumes"
	for dev in ${ahcidev} ${atadev} ${lvmvol} ${raidvol}; do
		if cryptomount "${dev}" ; then break ; fi
	done
	set pager=1
	echo

	# after cryptomount, lvm volumes might be available
	for vol in ${lvmvol}; do
		try_user_config "${vol}"
	done

	search_grub crypto

	for vol in lvm/* ; do
		try_user_config "${vol}"
	done

	# bruteforce as a last result. figure out how to boot
	# linux without a grub configuration file. (crypto and lvm unsupported)
	set vmlinuz=""
	set initrd=""
	set devtype=""
	set devnum=""
	set devletter=""
	set partnum=""
	for t in ata ahci; do
		set vmlinuz=""
		set initrd=""
		if [ "${t}" = "ata" ] && [ "${grub_scan_disk}" = "ahci" ]; then
			continue
		elif [ "${t}" = "ahci" ] && [ "${grub_scan_disk}" = "ata" ]; then
			continue
		fi
		for dev in 0 1 2 3 4 5 6 7 8; do
			for part in 1 2 3 4 5 6 7 8 9; do
				set root="${t}${devnum},${partnum}"
				set devnum="${dev}"
				set partnum="${part}"
				for k in /vmlinuz* @/vmlinuz*; do
					if [ ! -f "${k}" ] || [ ! -d /boot ]; then
						continue
					fi
					set vmlinuz="${k}"
					# do not break. if furthe rentries are
					# available, due to alphabetic sorting,
					# the next entry is likely a newer
					# kernel version
				done
				for k in /boot/vmlinuz* @/boot/vmlinuz*; do
					if [ "${vmlinuz}" != "" ]; then
						break
					fi
					set vmlinuz="${k}"
				done
				if [ "${vmlinuz}" = "" ]; then
					continue
				fi
				for i in /initrd* /initramfs* @/initrd* @/initramfs*; do
					if [ ! -f "${i}" ] || [ ! -d "/boot" ]; then
						continue
					done
					set initrd="${i}"
					# ditto. do not break yet
				done
				for i in /boot/initrd* /boot/initramfs* @/boot/initrd* @/boot/initramfs*; do
					if [ "${initrd}" != "" ]; then
						break
					fi
					set initrd="${i}"
				done
				if [ "${vmlinuz}" != "" ] && [ "${initrd}" != "" ]; then
					set devtype="${t}"
					break
				fi
				set vmlinuz=""
				set initrd=""
			done
			if [ "${vmlinuz}" != "" ] && [ "${initrd}" != "" ]; then
				break
			fi
		done
		if [ "${vmlinuz}" != "" ] && [ "${initrd}" != "" ]; then
			break
		fi
	done

	if [ "${vmlinuz}" = "" ] || [ "${initrd}" = "" ]; then
		return
	fi
	if [ "${devnum}" = "0" ]; then
		set devletter="a"
	elif [ "${devnum}" = "1" ]; then
		set devletter="b"
	elif [ "${devnum}" = "2" ]; then
		set devletter="c"
	elif [ "${devnum}" = "3" ]; then
		set devletter="d"
	elif [ "${devnum}" = "4" ]; then
		set devletter="e"
	elif [ "${devnum}" = "5" ]; then
		set devletter="f"
	elif [ "${devnum}" = "6" ]; then
		set devletter="g"
	elif [ "${devnum}" = "7" ]; then
		set devletter="h"
	elif [ "${devnum}" = "8" ]; then
		set devletter="i"
	fi
	set btrfsvol=""
	if [ "${vmlinuz#@}" != "${vmlinuz}" ]; then
		set btrfsvol="rootflags=subvol=@"
	fi
	set root="${devtype}${devnum},${partnum}"
	linux ${vmlinuz} root=/dev/sd${devletter}${partnum} ${btrfsvol} rw
	initrd ${initrd}

	true # Prevent pager requiring to accept each line instead of whole screen
}

menuentry 'Find and load GRUB config from USB drive  [s]' --hotkey='s' {
	search_grub usb
}
menuentry 'Find and load ISOLINUX/EXTLINUX from USB drive  [u]' --hotkey='u' {
	search_isolinux usb
}
menuentry 'Find and load ISOLINUX/EXTLINUX menu via AHCI  [a]' --hotkey='a' {
	search_isolinux ahci
}
menuentry 'Find and load ISOLINUX/EXTLINUX menu via ATA/IDE  [d]' --hotkey='d' {
	search_isolinux ata
}
if [ -f (cbfsdisk)/grubtest.cfg ]; then
menuentry 'Load test configuration (grubtest.cfg) inside of CBFS  [t]' --hotkey='t' {
	set root='(cbfsdisk)'
	if [ -f /grubtest.cfg ]; then
		configfile /grubtest.cfg
	fi
}
fi
if [ -f (cbfsdisk)/seabios.elf ]; then
menuentry 'Load SeaBIOS (payload) [b]' --hotkey='b' {
	set root='cbfsdisk'
	chainloader /seabios.elf
}
fi
if [ -f (cbfsdisk)/img/grub2 ]; then
menuentry 'Return to SeaBIOS [b]' --hotkey='b' {
	set root='cbfsdisk'
	chainloader /fallback/payload
}
fi
menuentry 'Poweroff  [p]' --hotkey='p' {
	halt
}
menuentry 'Reboot  [r]' --hotkey='r' {
	reboot
}
if [ -f (cbfsdisk)/img/memtest ]; then
menuentry 'Load MemTest86+  [m]' --hotkey='m' {
	set root='cbfsdisk'
	chainloader /img/memtest
}
fi
